-----------------------------------------------------------------------------
--
-- Module      :  Data.Units.Example
-- Copyright   :
-- License     :  AllRightsReserved
--
-- Maintainer  :  eduard.sergeev@gmail.com
-- Stability   :  Highly Experimental
-- Portability :
--
-- | Examples of usagage
--
-----------------------------------------------------------------------------

{-# LANGUAGE RebindableSyntax, TemplateHaskell, QuasiQuotes,
TypeFamilies, TypeOperators,
ScopedTypeVariables #-}
{-# OPTIONS_GHC -fcontext-stack=128 #-}

module Data.Units.Example where

import Data.Function
import Prelude (Fractional, Double, Num, Eq(..), print, undefined)
import qualified Prelude as P

import Data.Units
import Data.Units.SI




-- | Different ways to define g=9.8<m/s^2>
g = 9.8<:_m/(_s*_s)       -- show g4 ==> 9.8<m/s^2>

g2 = quantitify 9.8 :: Double ::: [unit| M/S^2 |]   -- show g2 ==> 9.8<m/s^2>

[unit| Test(tt)_tt=M^5*S^2/K^3 |]

v1 = g * 5<:_s                       -- show v1 ==> 49.0<m/s>

s1 = v1 * 3<:_s                      -- show s1 ==> 147.0<m>

-- ferr = v1 + s1                          -- error!

dv = v1 - g * 2<:_s                  -- show dv ==> 29.4<m/s>

s2 = 10<:_m/_s * 5<:_s - 1<:_m               -- show s2 ==> 49.0<m>

v2 = _A * _O
el1 = 1<:_A * 220<:_O :: (Double ::: V)

-- | Custom base unit - length in feet
-- Base unit must not be based on other units (hence it's 'base')
-- User must specify a valid data type name for it (like 'Ft') and an unique index (like 6)
-- Optionaly the following can also be specified:
-- - conversion function - must by in parentheses: like (feet) - default: no function is generated
-- - diplay(show) name - must be in angle brackets: like <ft> - default: data type name is used
-- - unit variable name (==1) - must be specified between conversion function and display name - like f - default: no variable is generated
[unit| Ft(feet)_ft<ft>:10 |] 

feetPerMetre = 3.28084<:_ft / _m

-- 6 feet in metres
sixfeet = feet 6 / feetPerMetre

-- another way to specify unit via "(<:)" operator (Mount Everest in feet)
everest = feetPerMetre * 8848<:_m          -- show everest ==> 29028.87232<ft>


-- | Custom derived unit - speed in m/s
-- Derived unit must be expressed via other units (base or derived)
[unit| Vms(speed)vms = M/S |]

-- | Direct way to specify unitified signature
sqrSpeed1 :: Num n => (n ::: Vms) -> (n ::: [unit| Vms*Vms |])
sqrSpeed1 x = x*x

-- | '(>|)' restricts 'x' to be of Vms measure
sqrSpeed2 x = (x>|vms)*x

-- | Requires ScopedTypeVariables extension
sqrSpeed3 (x :: Double ::: Vms) = x*x


-- | temperature, Celsius/Centigrade
[unit| Cdg(celcius)<C>:8 |] 
-- |temperature, Fahrenheit
[unit| Fdg(fahrenheit)<F>:9 |] 

convertCtoF :: Double ::: Cdg -> Double ::: Fdg
convertCtoF temp = fahrenheit 9.0 / celcius 5.0 * temp + fahrenheit 32.0

convertFtoC temp = celcius 5.0 / fahrenheit 9.0 * (temp - fahrenheit 32.0)

f1 = convertCtoF (celcius 36.6)      --  show f1 ==> 97.88000000000001<Fd>
c1 = convertFtoC (fahrenheit 451)    --  show c1 ==> 232.7777777777778<Cd>

-- | These are voltsc
--vs :: Double ::: V
--vs = 34<:ohm * 1<:ampere

--vs2 = unify 5 :: Double ::: FV

[unit| Gk(gks) = GG*GG*GG |]

[unit| GG(gg) = M*S |]

--gg1 = quantitify 5 :: Double ::: GG

--gk2 = 1<:s / (gks 6 * gks 6 / seconds 4)
--gk = gg 5 * gg 5 * gg 5 * gg 5 * gg 5 * gg 5

--speed :: Double ::: M -> Double :::S -> Double ::: M :/: S
--speed m s = m / s



--vo1 = sqrt (5<:volt * 10<:volt)
--vo2 = sqrt (5<:volt)  -- error

--asm :: P.Integer ::: (M :*: S :*: A)
--asm = ampere*second*meter

{-
type MS = U :*: M :*: M :*: M :*: M
type MM = U :*: S :*: S :*: S :*: S :*: S :*: S :*: S :*: S :*: S :*: S
type MCD = U :*: Cd :*: Cd :*: Cd :*: Cd :*: Cd :*: Cd :*: Cd
type US = Union MCD (U :*: S :*: S)
sp = undefined :: US
-}
